﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Transactions;
using Microsoft.Practices.Unity;
using Wyn.PMS.Common.NightAudit;
using Wyn.PMS.Common.Utils;
using Wyn.PMS.Entity.Entities;
using Wyn.PMS.Entity.IDataAccess;

namespace Wyn.PMS.Test.Cache
{
    public class FixAnalysis
    {
        private static readonly IUnityContainer container = UnityContainerService.GetContainer();

        internal void Analysis(string hotelId, DateTime today, IList<Account> notRollAccounts, IDictionary<string, decimal> rtRoomFeeAccounts, IList<RoomType> roomTypes, IList<Order> allRollOrders, IList<Order> fullDayOrders, bool changeValidCount)
        {
            IAnalysisSubjectRepository analysisSubjectRepository = container.Resolve<IAnalysisSubjectRepository>();

            INaOperationAnalysisRepository analysisRepository = container.Resolve<INaOperationAnalysisRepository>();

            IOvertimeDiscountRepository overtimeDiscountRepository = container.Resolve<IOvertimeDiscountRepository>();

            var transactionOptions = new TransactionOptions();

            transactionOptions.IsolationLevel = IsolationLevel.ReadUncommitted;

            var subjects = analysisSubjectRepository.BatchFind(hotelId, a => a.IsValid);

            var checkInTypes = GetCheckInTypes();

            var guestSources = GetGuestSources();

            var channelInfos = GetChannelInfos(hotelId);

            IList<NaOperationAnalysis> analysisList = new List<NaOperationAnalysis>();
            
            var validRoomCount = roomTypes.Sum(r => r.TotalRooms);
            
            DateTime lastMonthToday = today.AddMonths(-1);

            Expression<Func<NaOperationAnalysis, bool>> lastMonthExp = a => a.HotelID == hotelId && a.BizDay == lastMonthToday;
            
            DateTime lastYearToday = today.AddYears(-1);

            Expression<Func<NaOperationAnalysis, bool>> lastYearExp = a => a.HotelID == hotelId && a.BizDay == lastYearToday;
            
            DateTime yesterday = today.AddDays(-1);

            Expression<Func<NaOperationAnalysis, bool>> yesterdayExp = a => a.HotelID == hotelId && a.BizDay == yesterday;
            
            Expression<Func<OvertimeDiscount, bool>> discountExp = o => o.BizDay == today && o.HotelID == hotelId;

            IList<NaOperationAnalysis> lastMonthTodayAnalysisList;
            IList<NaOperationAnalysis> lastYearTodayAnalysisList;
            IList<NaOperationAnalysis> yesterdayAnalysisList;
            IList<OvertimeDiscount> discounts;

            using (var scope = new TransactionScope(TransactionScopeOption.Required, transactionOptions))
            {
                lastMonthTodayAnalysisList = analysisRepository.BatchFind(hotelId, lastMonthExp);

                lastYearTodayAnalysisList = analysisRepository.BatchFind(hotelId, lastYearExp);

                yesterdayAnalysisList = analysisRepository.BatchFind(hotelId, yesterdayExp);

                discounts = overtimeDiscountRepository.BatchFind(hotelId, discountExp);

                scope.Complete();
            }

            foreach (var item in subjects)
            {
                NaOperationAnalysis analysis = AnalysisSubject(item,hotelId,today, notRollAccounts,allRollOrders,fullDayOrders, discounts, validRoomCount);

                if (analysis != null)
                {
                    FillOtherInfo(today, yesterdayAnalysisList, lastMonthTodayAnalysisList,
                                  lastYearTodayAnalysisList, analysis, item.Code);

                    analysisList.Add(analysis);
                }
            }
            
            foreach (var type in checkInTypes)
            {
                NaOperationAnalysis analysis = AnalysisCheckIntype(type, hotelId, today, notRollAccounts, allRollOrders, fullDayOrders, validRoomCount);

                var CITAnalysisCode = GlobalConst.ANALYSIS_PREFIX_CHECKIN_TYPE + type.Key;

                FillOtherInfo(today, yesterdayAnalysisList, lastMonthTodayAnalysisList, lastYearTodayAnalysisList, analysis, CITAnalysisCode);

                analysisList.Add(analysis);
            }

            foreach (var source in guestSources)
            {
                NaOperationAnalysis analysis = AnalysisSource(source, hotelId, today, allRollOrders, fullDayOrders, notRollAccounts, validRoomCount);

                var GSCAnalysisCode = GlobalConst.ANALYSIS_PREFIX_GSC + source.Key;

                FillOtherInfo(today, yesterdayAnalysisList, lastMonthTodayAnalysisList, lastYearTodayAnalysisList, analysis, GSCAnalysisCode);

                analysisList.Add(analysis);
            }

            foreach (var channel in channelInfos)
            {
                NaOperationAnalysis analysis = AnalysisChannel(channel, hotelId,today, notRollAccounts, allRollOrders,fullDayOrders, validRoomCount);

                var CHAAnalysisCode = GlobalConst.ANALYSIS_PREFIX_CHANNEL + channel.ID.ToString();

                FillOtherInfo(today, yesterdayAnalysisList, lastMonthTodayAnalysisList, lastYearTodayAnalysisList, analysis, CHAAnalysisCode);

                analysisList.Add(analysis);
            }

            foreach (var roomtype in roomTypes)
            {
                var rtFee = rtRoomFeeAccounts[roomtype.RoomTypeID];
                
                NaOperationAnalysis analysis = AnalysisRoomType(roomtype, hotelId, today, rtFee,fullDayOrders);

                var RTAnalysisCode = GlobalConst.ANALYSIS_PREFIX_RT + roomtype.RoomTypeID;

                FillOtherInfo(today, yesterdayAnalysisList, lastMonthTodayAnalysisList, lastYearTodayAnalysisList, analysis, RTAnalysisCode);

                analysisList.Add(analysis);

                NaOperationAnalysis analysisInRoom = AnalysisRoomTypeInRoom(roomtype,hotelId,today,fullDayOrders, notRollAccounts,allRollOrders);

                analysisInRoom.ValidTodayTotal = analysis.ValidTodayTotal;

                FillOtherInfo(today, yesterdayAnalysisList, lastMonthTodayAnalysisList, lastYearTodayAnalysisList, analysisInRoom, analysisInRoom.ItemCode);

                analysisList.Add(analysisInRoom);
            }
            
            var oldAnalysis= analysisRepository.BatchFind(hotelId, a => a.HotelID == hotelId && a.BizDay == today);

            IList<NaOperationAnalysis> updates = new List<NaOperationAnalysis>();

            IList<NaOperationAnalysis> adds = new List<NaOperationAnalysis>();

            foreach (var analysis in analysisList)
            {
                if (oldAnalysis.Any(o => o.ItemCode == analysis.ItemCode))
                {
                    updates.Add(analysis);

                }
                else
                {
                    adds.Add(analysis);
                }
            }

            try
            {
                //IList<string> codes = new List<string>
                //    {"BDDA", "BDDR", "BDDS", "BDFR", "BDSA", "BDSR", "BDTR", "BDTS", "BSSR", "BSTR"};
                
                adds = adds.Where(a => a.ItemCode=="H08" || a.ItemCode=="H09").ToList();

                updates = updates.Where(a => a.ItemCode == "H08" || a.ItemCode == "H09").ToList();

                analysisRepository.BatchInsert(hotelId, adds);

                if (changeValidCount)
                {
                    analysisRepository.FixBatchUpdate(hotelId, updates);
                }
                else
                {
                    analysisRepository.BatchUpdate(hotelId, updates);
                    
                }
            }
            catch (Exception ex)
            {
                Common.SecurityControl.OperateLog.ErrorLog(ex.Message, ex);
            }
        }

        private NaOperationAnalysis AnalysisSubject(AnalysisSubject item, string hotelId, DateTime today, IList<Account> notRollAccounts, IList<Order> allRollOrders, IList<Order> fullDayOrders, IList<OvertimeDiscount> discounts, int validRoomCount)
        {
            NaOperationAnalysis ananlysis = new NaOperationAnalysis();

            ananlysis.HotelID = hotelId;

            ananlysis.BizDay = today;

            ananlysis.ItemCode = item.Code;

            ananlysis.ItemName = item.Name;

            ananlysis.ValidTodayTotal = validRoomCount;

            switch (item.Code)
            {
                case AnalysisSubjectCode.外宾数:

                    Func<Order, bool> tempExp = a => !string.IsNullOrEmpty(a.Country)
                                                                    && a.Country != GlobalConst.COUNTRY_中国
                                                                    && a.Country != GlobalConst.COUNTRY_台湾
                                                                    && a.Country != GlobalConst.COUNTRY_香港
                                                                    && a.Country != GlobalConst.COUNTRY_澳门;

                    var foreign = allRollOrders.Where(tempExp).ToList();

                    //ananlysis.TodayReceipts = SumReceipts(foreign, notRollAccounts, true);

                    ananlysis.TodayCount = fullDayOrders.Count(tempExp);

                    break;

                case AnalysisSubjectCode.内宾数:

                    Func<Order, bool> landExp = o => string.IsNullOrEmpty(o.Country)
                                                     || o.Country == GlobalConst.COUNTRY_中国;
                    var land = allRollOrders.Where(landExp).ToList();

                    //ananlysis.TodayReceipts = SumReceipts(land, notRollAccounts, true);

                    ananlysis.TodayCount = fullDayOrders.Count(landExp);

                    break;

                case AnalysisSubjectCode.港澳台数:

                    Func<Order, bool> HK_MAC_CN_Exp = o => !string.IsNullOrEmpty(o.Country)
                                            && (o.Country == GlobalConst.COUNTRY_台湾
                                                || o.Country == GlobalConst.COUNTRY_香港
                                                || o.Country == GlobalConst.COUNTRY_澳门);

                    var HK_MAC_CN = allRollOrders.Where(HK_MAC_CN_Exp).ToList();

                    //ananlysis.TodayReceipts = SumReceipts(HK_MAC_CN, notRollAccounts, true);

                    ananlysis.TodayCount = fullDayOrders.Count(HK_MAC_CN_Exp);

                    break;

                case AnalysisSubjectCode.租客合计:

                    //ananlysis.TodayReceipts = SumReceipts(allRollOrders, notRollAccounts, true);

                    ananlysis.TodayCount = fullDayOrders.Count();

                    break;

                case AnalysisSubjectCode.当日租项:

                    ananlysis.TodayReceipts = notRollAccounts.Where(a => a.LedgerCode == LedgerCode.半日租 || a.LedgerCode == LedgerCode.全日租).Sum(a => a.Balance);

                    ananlysis.TodayCount = notRollAccounts.Count(a => a.LedgerCode == LedgerCode.半日租 || a.LedgerCode == LedgerCode.全日租);

                    break;

                case AnalysisSubjectCode.全日租数:

                    ananlysis.TodayReceipts = notRollAccounts.Where(a => a.LedgerCode == LedgerCode.全日租).Sum(a => a.Balance);

                    ananlysis.TodayCount = notRollAccounts.Count(a => a.LedgerCode == LedgerCode.全日租);

                    break;
                case AnalysisSubjectCode.半日租数:

                    ananlysis.TodayReceipts = notRollAccounts.Where(a => a.LedgerCode == LedgerCode.半日租).Sum(a => a.Balance);

                    ananlysis.TodayCount = notRollAccounts.Count(a => a.LedgerCode == LedgerCode.半日租);

                    break;

                case AnalysisSubjectCode.减免房租:

                    ananlysis.TodayCount = discounts.Count;

                    ananlysis.TodayReceipts = discounts.Sum(d => d.Money);

                    break;

                case AnalysisSubjectCode.标准房租:

                    ananlysis.TodayReceipts = notRollAccounts.Where(a => a.LedgerCode == LedgerCode.标准房租).Sum(a => a.Balance);

                    ananlysis.TodayCount = notRollAccounts.Count(a => a.LedgerCode == LedgerCode.标准房租);

                    break;

                case AnalysisSubjectCode.钟点会员:

                    Func<Order, bool> hours_Exp = a => a.CheckInType == EnumHelper.GetCode(CheckInType.HR)
                                                       && a.GuestSourceType == EnumHelper.GetCode(GuestSourceType.IM);

                    var hours = allRollOrders.Where(hours_Exp).ToList();

                    //ananlysis.TodayReceipts = SumReceipts(hours, notRollAccounts, true);

                    ananlysis.TodayCount = fullDayOrders.Count(hours_Exp);

                    break;

                case AnalysisSubjectCode.白天会员:

                    Func<Order, bool> daysExp = a => a.CheckInType == EnumHelper.GetCode(CheckInType.DR)
                                                     && a.GuestSourceType == EnumHelper.GetCode(GuestSourceType.IM);

                    var days = allRollOrders.Where(daysExp).ToList();

                    //ananlysis.TodayReceipts = SumReceipts(days, notRollAccounts, true);

                    ananlysis.TodayCount = fullDayOrders.Count(daysExp);
                    break;
                case AnalysisSubjectCode.当日来店数:

                    var todayIn = fullDayOrders.Where(a => a.CheckInBizDay == today).ToList();
                    //ananlysis.TodayReceipts = SumReceipts(todayIn, notRollAccounts, true);
                    ananlysis.TodayCount = todayIn.Count();

                    break;
                case AnalysisSubjectCode.当日离店数:
                    var todayOut = fullDayOrders.Where(a => a.CheckOutBizDay.HasValue && a.CheckOutBizDay.Value == today).ToList();
                    //ananlysis.TodayReceipts = SumReceipts(todayOut, notRollAccounts, true);
                    ananlysis.TodayCount = todayOut.Count();
                    break;
                case AnalysisSubjectCode.折扣房数:
                    IList<Order> disOrders = GetDiscountOrders(fullDayOrders, today, true);
                    //ananlysis.TodayReceipts = SumReceipts(disOrders, notRollAccounts, true);
                    ananlysis.TodayCount = disOrders.Count();
                    break;

                case AnalysisSubjectCode.全价房数:
                    IList<Order> notDisOrders = GetDiscountOrders(fullDayOrders, today, false);
                    //ananlysis.TodayReceipts = SumReceipts(notDisOrders, notRollAccounts, true);
                    ananlysis.TodayCount = notDisOrders.Count();
                    break;

                case AnalysisSubjectCode.挂账金额:

                    ananlysis.TodayReceipts = notRollAccounts.Where(a => a.LedgerCode == LedgerCode.挂帐).Sum(a => a.Balance);

                    ananlysis.TodayCount = notRollAccounts.Count(a => a.LedgerCode == LedgerCode.挂帐);
                    break;

                case AnalysisSubjectCode.积分兑换:

                    Func<Order, bool> noFreeExp = a => a.CheckInType != EnumHelper.GetCode(CheckInType.HR)
                                         && a.CheckInType != EnumHelper.GetCode(CheckInType.DR)
                                         && a.ActivityCode == GlobalConst.POINT_EXCHANGE;

                    var noFree = allRollOrders.Where(noFreeExp).ToList();

                    ananlysis.TodayReceipts = SumReceipts(noFree, notRollAccounts, true);

                    ananlysis.TodayCount = fullDayOrders.Count(noFreeExp);

                    break;
                case AnalysisSubjectCode.招待房:
                    Func<Order, bool> receptSelfExp = a => a.CheckInType != EnumHelper.GetCode(CheckInType.DR)
                                                        && a.CheckInType != EnumHelper.GetCode(CheckInType.HR)
                                                        && a.ActivityCode == GlobalConst.POINT_RECEPT_SELF;

                    var receptSelf = allRollOrders.Where(receptSelfExp).ToList();

                    ananlysis.TodayReceipts = SumReceipts(receptSelf, notRollAccounts, true);

                    ananlysis.TodayCount = fullDayOrders.Count(receptSelfExp);

                    break;
                default:
                    return null;
            }

            return ananlysis;
        }

        private NaOperationAnalysis AnalysisCheckIntype(KeyValuePair<string, string> type, string hotelId, DateTime bizDay, IList<Account> notRollAccounts, IList<Order> allRollOrders, IList<Order> fullDayOrders, int validRoomCount)
        {
            NaOperationAnalysis ananlysis = new NaOperationAnalysis();

            ananlysis.HotelID = hotelId;

            ananlysis.BizDay = bizDay;

            ananlysis.ItemCode = GlobalConst.ANALYSIS_PREFIX_CHECKIN_TYPE + type.Key;

            ananlysis.ItemName = type.Value;

            ananlysis.ValidTodayTotal = validRoomCount;

            Func<Order, bool> exp = a => a.CheckInType == type.Key;

            //var accOrders = allRollOrders.Where(exp).ToList();

            //var orderIds = string.Join("','", accOrders.Select(o => o.OrderID));

            if (notRollAccounts != null && notRollAccounts.Any())
            {
                ananlysis.TodayReceipts = notRollAccounts.Where(a => a.CheckInType == type.Key
                                                                     && a.LedgerParentCode == LedgerCode.客房收入
                                                                     && a.LedgerCode != LedgerCode.全日租
                                                                     && a.LedgerCode != LedgerCode.半日租
                                                                     && !a.IsStrike).Sum(a => a.Balance);
            }

            ananlysis.TodayCount = fullDayOrders.Count(exp);

            return ananlysis;
        }

        private NaOperationAnalysis AnalysisSource(KeyValuePair<string, string> source, string hotelId, DateTime bizDay, IList<Order> allRollOrders, IList<Order> fullDayOrders, IList<Account> notRollAccounts, int validRoomCount)
        {
            NaOperationAnalysis ananlysis = new NaOperationAnalysis();

            ananlysis.HotelID = hotelId;

            ananlysis.BizDay = bizDay;

            ananlysis.ItemCode = GlobalConst.ANALYSIS_PREFIX_GSC + source.Key;

            ananlysis.ItemName = source.Value;

            ananlysis.ValidTodayTotal = validRoomCount;

            Func<Order, bool> exp = a => a.GuestSourceType == source.Key
                                         && a.CheckInType != EnumHelper.GetCode(CheckInType.DR)
                                         && a.CheckInType != EnumHelper.GetCode(CheckInType.HR);

            var orders = allRollOrders.Where(a => a.GuestSourceType == source.Key).ToList();

            ananlysis.TodayReceipts = SumReceipts(orders, notRollAccounts, true);

            ananlysis.TodayCount = fullDayOrders.Count(exp);

            return ananlysis;
        }

        private NaOperationAnalysis AnalysisChannel(ChannelInfo channel, string hotelId, DateTime bizDay, IList<Account> notRollAccounts, IList<Order> allRollOrders, IList<Order> fullDayOrders, int validRoomCount)
        {
            NaOperationAnalysis ananlysis = new NaOperationAnalysis();

            ananlysis.HotelID = hotelId;

            ananlysis.BizDay = bizDay;

            ananlysis.ItemCode = GlobalConst.ANALYSIS_PREFIX_CHANNEL + channel.ID.ToString();

            ananlysis.ItemName = channel.Name;

            ananlysis.ValidTodayTotal = validRoomCount;

            Func<Order, bool> exp = a => a.ChannelID == channel.ID
                                         && a.CheckInType != EnumHelper.GetCode(CheckInType.DR)
                                         && a.CheckInType != EnumHelper.GetCode(CheckInType.HR);

            var orders = allRollOrders.Where(a=>a.ChannelID == channel.ID).ToList();

            ananlysis.TodayReceipts = SumReceipts(orders, notRollAccounts, true);

            ananlysis.TodayCount = fullDayOrders.Count(exp);

            return ananlysis;
        }

        private NaOperationAnalysis AnalysisRoomType(RoomType roomtype, string hotelId,DateTime bizDay, decimal rtfee, IList<Order> fullDayOrders)
        {
            NaOperationAnalysis ananlysis = new NaOperationAnalysis();

            ananlysis.HotelID = hotelId;

            ananlysis.BizDay = bizDay;

            ananlysis.ItemCode = GlobalConst.ANALYSIS_PREFIX_RT + roomtype.RoomTypeID;

            ananlysis.ItemName = roomtype.RoomTypeName;

            ananlysis.TodayReceipts = rtfee;

            ananlysis.ValidTodayTotal = roomtype.TotalRooms;

            ananlysis.TodayCount = fullDayOrders.Count(a => a.RoomTypeID == roomtype.RoomTypeID
                                                            && a.CheckInType != EnumHelper.GetCode(CheckInType.DR)
                                                            && a.CheckInType != EnumHelper.GetCode(CheckInType.HR));

            return ananlysis;
        }
        
        private NaOperationAnalysis AnalysisRoomTypeInRoom(RoomType roomtype, string hotelId,DateTime bizDay, IList<Order> fullDayOrders, IList<Account> notRollAccounts,IList<Order> allRollOrders)
        {
            NaOperationAnalysis ananlysis = new NaOperationAnalysis();

            ananlysis.HotelID = hotelId;

            ananlysis.BizDay = bizDay;

            ananlysis.ItemCode = GlobalConst.ANALYSIS_PREFIX_RT_IN_ROOM + roomtype.RoomTypeID;

            ananlysis.ItemName = roomtype.RoomTypeName + GlobalConst.ANALYSIS_PREFIX_RT_IN_ROOM_NAME;

            ananlysis.ValidTodayTotal = roomtype.TotalRooms;

            Func<Order, bool> exp = o => o.RoomTypeID == roomtype.RoomTypeID
                                         && o.CheckInBizDay <= bizDay
                                         && ((o.CheckOutBizDay.HasValue && o.CheckOutBizDay > bizDay)
                                             || (!o.CheckOutBizDay.HasValue && o.DepartureDate.Date > bizDay))
                                         && o.CheckInType != EnumHelper.GetCode(CheckInType.DR)
                                         && o.CheckInType != EnumHelper.GetCode(CheckInType.HR);

            Func<Order, bool> rollExp = o => o.RoomTypeID == roomtype.RoomTypeID
                                         && o.CheckInBizDay <= bizDay
                                         && ((o.CheckOutBizDay.HasValue && o.CheckOutBizDay > bizDay)
                                             || (!o.CheckOutBizDay.HasValue && o.DepartureDate.Date > bizDay));

            var orders = allRollOrders.Where(rollExp).ToList();

            ananlysis.TodayReceipts = SumReceipts(orders, notRollAccounts, true);

            ananlysis.TodayCount = fullDayOrders.Count(exp);

            return ananlysis;
        }

        private void FillOtherInfo(DateTime today, IList<NaOperationAnalysis> yesterdayAnalysisList, IList<NaOperationAnalysis> lastMonthTodayAnalysisList, IList<NaOperationAnalysis> lastYearTodayAnalysisList, NaOperationAnalysis analysis, string code)
        {
            DateTime yesterday = today.AddDays(-1);
           
            var yesterdayAnalysis = (yesterdayAnalysisList != null && yesterdayAnalysisList.Any())
                                        ? yesterdayAnalysisList.FirstOrDefault(a => a.ItemCode == code)
                                        : null;

            if (yesterdayAnalysis != null && yesterday.Month == today.Month)
            {
                analysis.MonthReceipts = analysis.TodayReceipts + yesterdayAnalysis.MonthReceipts;

                analysis.MonthCount = analysis.TodayCount + yesterdayAnalysis.MonthCount;

                analysis.ValidMonthTotal = analysis.ValidTodayTotal + yesterdayAnalysis.ValidMonthTotal;

            }
            else
            {
                analysis.MonthReceipts = analysis.TodayReceipts;

                analysis.MonthCount = analysis.TodayCount;

                analysis.ValidMonthTotal = analysis.ValidTodayTotal;
            }

           
            if (yesterdayAnalysis != null && yesterday.Year == today.Year)
            {
                analysis.YearReceipts = analysis.TodayReceipts + yesterdayAnalysis.YearReceipts;

                analysis.YearCount = analysis.TodayCount + yesterdayAnalysis.YearCount;

                analysis.ValidYearTotal = analysis.ValidTodayTotal + yesterdayAnalysis.ValidYearTotal;

            }
            else
            {
                analysis.YearReceipts = analysis.TodayReceipts;

                analysis.YearCount = analysis.TodayCount;

                analysis.ValidYearTotal = analysis.ValidTodayTotal;
            }
           
            if (lastMonthTodayAnalysisList != null && lastMonthTodayAnalysisList.Any())
            {
                var lastMonthAnalysis = lastMonthTodayAnalysisList.FirstOrDefault(a => a.ItemCode == code);

                if (lastMonthAnalysis != null)
                {
                    analysis.LastMonthTodayReceipts = lastMonthAnalysis.TodayReceipts;

                    analysis.LastMonthTodayCount = lastMonthAnalysis.TodayCount;

                    analysis.ValidLastMonthTodayTotal = lastMonthAnalysis.ValidTodayTotal;
                }
            }
           
            if (lastYearTodayAnalysisList != null && lastYearTodayAnalysisList.Any())
            {
                var lastYearAnalysis = lastYearTodayAnalysisList.FirstOrDefault(a => a.ItemCode == code);

                if (lastYearAnalysis != null)
                {
                    analysis.LastYearMonthReceipts = lastYearAnalysis.MonthReceipts;

                    analysis.LastYearMonthCount = lastYearAnalysis.MonthCount;

                    analysis.LastYearReceipts = lastYearAnalysis.YearReceipts;

                    analysis.LastYearCount = lastYearAnalysis.YearCount;

                    analysis.ValidLastYearMonthTotal = lastYearAnalysis.ValidMonthTotal;

                    analysis.ValidLastYearTotal = lastYearAnalysis.ValidYearTotal;
                }
            }

        }

        private decimal SumReceipts(IEnumerable<Order> orders, IList<Account> notRollAccounts, bool isOnlyRoomFee)
        {
            IEnumerable<string> orderIds = orders.Select(o => o.OrderID);

            decimal receipts = 0;

            string CIT_HR = EnumHelper.GetCode(CheckInType.HR), CIT_DR = EnumHelper.GetCode(CheckInType.DR);

            if (notRollAccounts != null && notRollAccounts.Any())
            {
                if (isOnlyRoomFee)
                {
                    receipts = notRollAccounts
                        .Where(a => orderIds.Contains(a.CreateOrderID) && !a.IsStrike
                                    && a.CheckInType != CIT_HR
                                    && a.CheckInType != CIT_DR
                                    && a.LedgerParentCode == LedgerCode.客房收入
                                    && a.LedgerCode != LedgerCode.全日租
                                    && a.LedgerCode != LedgerCode.半日租)
                        .Sum(a => a.Balance);
                }
                else
                {
                    receipts = notRollAccounts
                        .Where(a => orderIds.Contains(a.CreateOrderID)
                                    && a.CheckInType != CIT_HR
                                    && a.CheckInType != CIT_DR
                                    && !a.IsStrike && a.LedgerParentCode == LedgerCode.客房收入)
                        .Sum(a => a.Balance);
                }
            }

            return receipts;
        }

        private IList<ChannelInfo> GetChannelInfos(string hotelId)
        {
            IChannelInfoRepository repository = container.Resolve<IChannelInfoRepository>();

            Expression<Func<ChannelInfo, bool>> exp = a => a.IsValid;

            return repository.BatchFind(hotelId, exp);
        }

        private IDictionary<string, string> GetGuestSources()
        {
            var guestSources = BizCodeCache
                .GetBizCode(GlobalConst.ROOT_HOTEL_ID, CodeHelper.GetParentKey(typeof(GuestSourceType).Name))
                .Where(k => k.IsValid)
                .ToDictionary(k => k.KeyValue, k => k.KeyName);

            return guestSources;
            #region
            //IDictionary<string, string> guestSources = new Dictionary<string, string>();

            //guestSources.Add(EnumHelper.GetCode(GuestSourceType.AM), "中介协议");
            //guestSources.Add(EnumHelper.GetCode(GuestSourceType.CM), "公司会员");
            //guestSources.Add(EnumHelper.GetCode(GuestSourceType.GP), "团队");
            //guestSources.Add(EnumHelper.GetCode(GuestSourceType.IM), "个人会员");
            //guestSources.Add(EnumHelper.GetCode(GuestSourceType.LP), "长包");
            //guestSources.Add(EnumHelper.GetCode(GuestSourceType.WI), "上门散客");

            //return guestSources;
            #endregion
        }

        public IDictionary<string, string> GetCheckInTypes()
        {
            //IDictionary<string,string> checkInTypes = new Dictionary<string, string>();

            var checkInTypes = BizCodeCache
                .GetBizCode(GlobalConst.ROOT_HOTEL_ID, CodeHelper.GetParentKey(typeof(CheckInType).Name))
                .Where(k => k.IsValid)
                .ToDictionary(k => k.KeyValue, k => k.KeyName);

            return checkInTypes;
            #region
            // 入住类型 维也纳 夜审操作分析
            //checkInTypes.Add(EnumHelper.GetCode(CheckInType.NS), "标准房");
            //checkInTypes.Add(EnumHelper.GetCode(CheckInType.DR), "白天房");
            //checkInTypes.Add(EnumHelper.GetCode(CheckInType.HR), "钟点房");
            //checkInTypes.Add(EnumHelper.GetCode(CheckInType.SU), "自用房");
            //checkInTypes.Add(EnumHelper.GetCode(CheckInType.FR), "免费房");
            //checkInTypes.Add(EnumHelper.GetCode(CheckInType.MF), "误机客");

            //return checkInTypes;
            #endregion
        }

        private static void BuildLettingRate(IList<Account> notRollAccounts, List<Order> orders, int validRoomCount, NaOperationAnalysis ananlysis)
        {
            var NsCount = orders.Count(a => a.CheckInType == EnumHelper.GetCode(CheckInType.NS));

            var HrCount = orders.Count(a => a.CheckInType == EnumHelper.GetCode(CheckInType.HR));

            var DrCount = orders.Count(a => a.CheckInType == EnumHelper.GetCode(CheckInType.DR));

            var SuCount = orders.Count(a => a.CheckInType == EnumHelper.GetCode(CheckInType.SU));

            var FrCount = orders.Count(a => a.CheckInType == EnumHelper.GetCode(CheckInType.FR));

            var ExFullCount = notRollAccounts.Count(k => k.LedgerCode == LedgerCode.全日租);

            var ExHalfCount = notRollAccounts.Count(k => k.LedgerCode == LedgerCode.半日租);

            var fp = FormulaProvider.Instance;

            var formula = fp.GetFormula(FormulaProvider.AvgRoomPrice);

            if (validRoomCount > 0)
            {
                ananlysis.TodayReceipts = Math.Round((decimal)(
                                                               ((NsCount / formula.CheckInType_NS
                                                                 + FrCount / formula.CheckInType_FR
                                                                 + HrCount / formula.CheckInType_HR
                                                                 + DrCount / formula.CheckInType_DR
                                                                 + SuCount / formula.CheckInType_SU
                                                                 + ExFullCount / formula.Ledger_ExtraFullDay
                                                                 + ExHalfCount / formula.Ledger_ExtraHalfDay)
                                                                / validRoomCount) * 100), 2);
            }

            ananlysis.TodayCount = NsCount + FrCount + HrCount + DrCount + SuCount + ExFullCount + ExHalfCount / 2;
        }

        private IList<Order> GetDiscountOrders(IList<Order> orders, DateTime today, bool isDiscount)
        {
            IList<Order> disOrders = new List<Order>();

            IList<Order> notDisOrders = new List<Order>();

            foreach (var order in orders)
            {
                if (order.PriceDetail != null && order.PriceDetail.Count > 0)
                {
                    var price = order.PriceDetail.FirstOrDefault(b => b.BizDay == today) ??
                                order.PriceDetail.FirstOrDefault();

                    if (price != null)
                    {
                        if (price.Price != price.NormalPrice)
                        {
                            disOrders.Add(order);
                        }
                        else
                        {
                            notDisOrders.Add(order);
                        }
                    }
                    else
                    {
                        notDisOrders.Add(order);
                    }
                }
            }

            return isDiscount ? disOrders : notDisOrders;
        }

    }
}
